/**
 * Copyright 2015-现在 广州市领课网络科技有限公司
 */
package com.roncoo.education.util.polyv;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.collections4.map.HashedMap;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.aliyun.oas.utils.StringUtil;
import com.ning.http.util.Base64;
import com.roncoo.education.util.config.SystemUtil;
import com.roncoo.education.util.tools.JSONUtil;
import com.roncoo.education.util.tools.MD5Util;
import com.roncoo.education.util.tools.SHA1Util;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.http.HttpUtil;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 保利威视工具类
 *
 * @author wujing
 */
public final class PolyvUtil {

	private static final Logger logger = LoggerFactory.getLogger(PolyvUtil.class);

	private static final String KEY = "roncoo-cloud"; // 长度为12
	private static final String CHARSET_UTF_8 = "UTF-8";

	private PolyvUtil() {
	}

	/**
	 * 获取code
	 * 
	 * @param polyvCode
	 * @return
	 */
	public static String getPolyvCode(PolyvCode polyvCode) {
		try {
			return HttpUtil.encode(
					Base64.encode(SecureUtil.des(Base64.decode(KEY)).encrypt(JSONUtil.toJSONString(polyvCode))),
					CHARSET_UTF_8);
		} catch (Exception e) {
			logger.error("保利威视，加密出错", e);
			return "";
		}
	}

	/**
	 * code解密
	 * 
	 * @param code
	 * @return
	 */
	public static PolyvCode decode(String code) {
		try {
			return JSONUtil.parseObject(new String(
					SecureUtil.des(Base64.decode(KEY)).decrypt(Base64.decode(HttpUtil.decode(code, CHARSET_UTF_8)))),
					PolyvCode.class);
		} catch (Exception e) {
			logger.error("保利威视，解密出错", e);
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public static PolyvSignResult getSignForH5(PolyvSign bo, String useid, String secretkey) {
		// 根据时间戳、vid、密钥生成sign值
		String ts = String.valueOf(System.currentTimeMillis());

		// 获取播放token
		Map<String, Object> map = new HashedMap<>();
		map.put("userId", useid);
		map.put("videoId", bo.getVid());
		map.put("ts", ts);
		map.put("viewerIp", bo.getIp());
		map.put("viewerName", bo.getUserNo());
		map.put("extraParams", "HTML5");
		map.put("viewerId", bo.getUserNo());
		String concated = "extraParams" + map.get("extraParams") + "ts" + map.get("ts") + "userId" + map.get("userId")
				+ "videoId" + map.get("videoId") + "viewerId" + map.get("viewerId") + "viewerIp" + map.get("viewerIp")
				+ "viewerName" + map.get("viewerName");
		map.put("sign", MD5Util.MD5(secretkey + concated + secretkey).toUpperCase());
		String result = post(SystemUtil.POLYV_GETTOKEN, map);
		logger.info("保利威视，获取token接口：result={}", result);
		Map<String, Object> resultMap = JSONUtil.parseObject(result, HashMap.class);
		int code = Integer.valueOf(resultMap.get("code").toString()).intValue();
		if (code != 200) {
			return null;
		}
		Map<String, Object> data = (Map<String, Object>) resultMap.get("data");
		if (data == null || data.isEmpty()) {
			return null;
		}
		PolyvSignResult dto = new PolyvSignResult();
		dto.setSign(MD5Util.MD5(secretkey + bo.getVid() + ts));
		dto.setTs(ts);
		dto.setToken(data.get("token").toString());
		return dto;
	}

	public static UploadFileResult getVideo(String vid, String secretkey, String useid) {
		Map<String, Object> param = new TreeMap<String, Object>();
		param.put("vid", vid);
		param.put("format", "json");
		param.put("ptime", String.valueOf(System.currentTimeMillis()));// 当前13位毫秒级时间戳
		StringBuilder signStr = new StringBuilder();
		for (Map.Entry<String, Object> entry : param.entrySet()) {
			signStr.append("&").append(entry.getKey()).append("=").append(entry.getValue());
		}
		signStr = signStr.deleteCharAt(0);
		signStr.append(secretkey);
		param.put("sign", SHA1Util.getSign(signStr.toString()));
		String s = post("http://api.polyv.net/v2/video/{userid}/get-video-msg".replace("{userid}", useid), param);
		try {
			@SuppressWarnings("unchecked")
			Map<String, Object> m = JSONUtil.parseObject(s, HashMap.class);
			if (m.get("code").toString().equals("200")) {
				// 成功
				return JSONUtil.parseArray(JSONUtil.toJSONString(m.get("data")), UploadFileResult.class).get(0);
			}
			logger.error("获取视频失败，原因为：{}", s);
		} catch (Exception e) {
			logger.error("获取视频失败异常，结果={}，参数={}", s, param);
		}
		return null;
	}

	/**
	 * 上传视频 http://dev.polyv.net/2014/videoproduct/v-api/v-api-upload/uploadfile/
	 *
	 * @param file
	 * @return
	 */
	public static UploadFileResult uploadFile(File file, UploadFile uploadFile, String writetoken) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("writetoken", writetoken);
		param.put("JSONRPC", "{\"title\": \"" + uploadFile.getTitle() + "\", \"tag\": \"" + uploadFile.getTag()
				+ "\", \"desc\": \"" + uploadFile.getDesc() + "\"}");
		param.put("cataid", uploadFile.getCataid());
		if (StringUtil.isNotBlank(uploadFile.getWatermark())) {
			param.put("watermark", uploadFile.getWatermark());
		}
		String result = postFile(SystemUtil.POLYV_UPLOADVIDEO, param, file);
		try {
			JSONObject json = JSONObject.fromObject(result);
			if ("0".equals(json.getString("error"))) {
				return JSONUtil.parseArray(json.getString("data"), UploadFileResult.class).get(0);
			}
		} catch (Exception e) {
			logger.error(e.toString(), e);
		}
		logger.error("保利威视，上传视频失败，原因={}", result);
		return null;
	}

	/**
	 * 删除视频
	 */
	public static String deleteFile(String vid, String useid, String secretkey) {
		SortedMap<String, String> paramMap = new TreeMap<>();
		paramMap.put("userid", useid);// 用户ID
		paramMap.put("vid", vid);// 视频ID
		paramMap.put("ptime", String.valueOf(System.currentTimeMillis()));// 当前13位毫秒级时间戳
		StringBuilder signStr = new StringBuilder();
		for (Map.Entry<String, String> entry : paramMap.entrySet()) {
			signStr.append("&").append(entry.getKey()).append("=").append(entry.getValue());
		}
		signStr = signStr.deleteCharAt(0);
		signStr.append(secretkey);
		String sign = SHA1Util.getSign(signStr.toString());
		paramMap.put("sign", sign);
		String url = SystemUtil.POLYV_DELETEVIDEO.replace("{userid}", useid);
		HttpPost httpPost = new HttpPost(url.trim());
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
				.setConnectionRequestTimeout(3600000).setSocketTimeout(3600000).build();
		httpPost.setConfig(requestConfig);
		List<BasicNameValuePair> nvps = new ArrayList<>();
		for (Map.Entry<String, String> entry : paramMap.entrySet()) {
			nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
		}
		StringEntity se = null;
		try {
			se = new UrlEncodedFormEntity(nvps, CHARSET_UTF_8);
			httpPost.setEntity(se);
			HttpResponse httpResponse = HttpClientBuilder.create().build().execute(httpPost);
			return EntityUtils.toString(httpResponse.getEntity(), CHARSET_UTF_8);
		} catch (Exception e) {
			logger.error("保利威视，删除视频失败");
		}
		return null;
	}

	/**
	 * 上传问题接口
	 */
	public static QuestionResult uploadQuestion(Question question, String writetoken) {
		try {
			String url = SystemUtil.POLYV_QUESTION;
			HttpPost httpPost = new HttpPost(url.trim());
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
					.setConnectionRequestTimeout(3600000).setSocketTimeout(3600000).build();
			httpPost.setConfig(requestConfig);
			JSONArray choices = new JSONArray();
			for (String value : question.getAnswerList()) {
				JSONObject answer = new JSONObject();
				answer.put("answer", value);
				choices.add(answer);
			}
			JSONObject righeAnswer = new JSONObject();
			righeAnswer.put("answer", question.getRightAnswer());
			righeAnswer.put("right_answer", question.getRight());
			choices.add(righeAnswer);
			List<BasicNameValuePair> nvps = new ArrayList<>();
			nvps.add(new BasicNameValuePair("method", "saveExam"));
			nvps.add(new BasicNameValuePair("writetoken", writetoken));
			nvps.add(new BasicNameValuePair("vid", question.getVid()));
			nvps.add(new BasicNameValuePair("examId", question.getExamId()));
			nvps.add(new BasicNameValuePair("seconds", String.valueOf(question.getSeconds())));
			nvps.add(new BasicNameValuePair("question", question.getQuestion()));
			nvps.add(new BasicNameValuePair("choices", choices.toString()));
			nvps.add(new BasicNameValuePair("skip", String.valueOf(question.isSkip())));
			nvps.add(new BasicNameValuePair("answer", question.getAnswer()));
			nvps.add(new BasicNameValuePair("wrongShow", String.valueOf(question.getWrongShow())));
			nvps.add(new BasicNameValuePair("wrongTime", String.valueOf(question.getWrongTime())));
			StringEntity se = new UrlEncodedFormEntity(nvps, CHARSET_UTF_8);
			httpPost.setEntity(se);
			HttpResponse httpResponse = HttpClientBuilder.create().build().execute(httpPost);
			String resultStr = EntityUtils.toString(httpResponse.getEntity(), CHARSET_UTF_8);
			return (QuestionResult) JSONObject.toBean(JSONObject.fromObject(resultStr), QuestionResult.class);
		} catch (Exception e) {
			logger.error("添加问题失败！");
		}
		return null;
	}

	/**
	 * 获取sign
	 * 
	 * @param paramMap
	 * @return
	 */
	public static String getSign(Map<String, Object> paramMap, String secretkey) {
		if (paramMap.isEmpty()) {
			return "";
		}
		SortedMap<String, Object> smap = new TreeMap<String, Object>(paramMap);
		StringBuffer stringBuffer = new StringBuffer();
		for (Map.Entry<String, Object> m : smap.entrySet()) {
			String value = String.valueOf(m.getValue());
			if (StringUtils.hasText(value)) {
				stringBuffer.append(m.getKey()).append("=").append(value).append("&");
			}
		}
		stringBuffer.delete(stringBuffer.length() - 1, stringBuffer.length());
		String argPreSign = stringBuffer.append("&paySecret=").append(secretkey).toString();
		return MD5Util.MD5(argPreSign).toUpperCase();
	}

	/**
	 * @param url
	 * @param param
	 * @return
	 */
	public static String post(String url, Map<String, Object> param) {
		CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
		try {
			HttpPost httpPost = new HttpPost(url.trim());
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
					.setConnectionRequestTimeout(3600000).setSocketTimeout(3600000).build();
			httpPost.setConfig(requestConfig);
			List<NameValuePair> list = new ArrayList<>();
			for (Map.Entry<String, Object> m : param.entrySet()) {
				list.add(new BasicNameValuePair(m.getKey(), m.getValue().toString()));
			}
			httpPost.setEntity(new UrlEncodedFormEntity(list, "utf-8"));
			HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
			return EntityUtils.toString(httpResponse.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				closeableHttpClient.close();
			} catch (IOException e) {
			}
		}
		return "";
	}

	private static String postFile(String url, Map<String, Object> param, File file) {
		CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
		try {
			HttpPost httpPost = new HttpPost(url.trim());
			httpPost.setConfig(RequestConfig.custom().setConnectTimeout(10000).setConnectionRequestTimeout(3600000)
					.setSocketTimeout(3600000).build());
			MultipartEntityBuilder entity = MultipartEntityBuilder.create();
			entity.addPart("Filedata", new FileBody(file));
			ContentType contentType = ContentType.create("text/plain", Charset.forName(CHARSET_UTF_8));
			for (Map.Entry<String, Object> m : param.entrySet()) {
				entity.addPart(m.getKey(), new StringBody(m.getValue().toString(), contentType));
			}
			httpPost.setEntity(entity.build());
			return EntityUtils.toString(closeableHttpClient.execute(httpPost).getEntity(), CHARSET_UTF_8);
		} catch (Exception e) {
			logger.error("上传到保利威视失败，url={},param={}", url, param, e);
		} finally {
			try {
				closeableHttpClient.close();
			} catch (IOException e) {
			}
		}
		return "";
	}

}
